#include "stdafx.h"
#include "sdlvlc.h"

SDL_Rect fullScreenRect;

sdl_exception::sdl_exception(char* format, ...)
{
	char tmp[1024];
	va_list args;
	va_start (args, format);
	vsprintf_s (tmp, _countof(tmp), format, args);
	va_end (args);
}

// VLC prepares to render a video frame.
void* vlc_window::lock(void *data, void **pixels) 
{
	vlc_window *pThis = reinterpret_cast<vlc_window *>(data);

	int pitch = 0;

	SDL_LockMutex(pThis->mutex);
	SDL_LockTexture(pThis->texture, NULL, pixels, &pitch);

	return NULL; // Picture identifier, not needed here.
}

// VLC just rendered a video frame.
void vlc_window::unlock(void *data, void *id, void *const *pixels) 
{
	vlc_window *pThis = reinterpret_cast<vlc_window *>(data);

	SDL_UnlockTexture(pThis->texture);
	SDL_UnlockMutex(pThis->mutex);
}

// VLC wants to display a video frame.
void vlc_window::display(void *data, void *id) 
{
	vlc_window *pThis = reinterpret_cast<vlc_window *>(data);

	//SDL_RenderClear(c->renderer);
	SDL_RenderCopy(pThis->renderer, pThis->texture, NULL, &fullScreenRect);
	SDL_RenderPresent(pThis->renderer);
}

vlc_window::vlc_window(int display) : displayNumber(display)
{
	char const *vlc_argv[] = 
	{
		//"--no-audio", // Don't play audio.
		"--no-xlib", // Don't use Xlib.
	};

	int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);

	// Initialise libSDL.
	if (SDL_Init(SDL_INIT_VIDEO) < 0) 
	{
		throw ("Could not initialize SDL: %s.\n", SDL_GetError());
	}

	MYEVT_LOAD  = SDL_RegisterEvents(6);
	MYEVT_PLAY  = MYEVT_LOAD + 1;
	MYEVT_PAUSE = MYEVT_LOAD + 2;
	MYEVT_STOP  = MYEVT_LOAD + 3;
	MYEVT_CLS   = MYEVT_LOAD + 4;
	MYEVT_TEST  = MYEVT_LOAD + 5;

	int num = SDL_GetNumVideoDisplays(); 
	std::vector<SDL_Rect> displays(num);
	for ( int i=0; i < num; i++ ) 
	{
		SDL_GetDisplayBounds( i, &displays[i] ); 
	}

	fullScreenRect = displays[displayNumber];
	fullScreenRect.x = 0;
	fullScreenRect.y = 0;

		// Create SDL graphics objects.
	SDL_Window * window = SDL_CreateWindow(
			"Player",
			displays[displayNumber].x,
			displays[displayNumber].y,
			displays[displayNumber].w, 
			displays[displayNumber].h,
			SDL_WINDOW_BORDERLESS | SDL_WINDOW_SHOWN);

	if (!window) 
	{
		throw sdl_exception("Couldn't create window: %s\n", SDL_GetError());
	}

	renderer = SDL_CreateRenderer(window, -1, 0);
	if (!renderer) 
	{
		throw sdl_exception("Couldn't create renderer: %s\n", SDL_GetError());
	}

	do_clearscreen();

	texture = SDL_CreateTexture(
			renderer,
			SDL_PIXELFORMAT_BGR565, SDL_TEXTUREACCESS_STREAMING,
			fullScreenRect.w, fullScreenRect.h);

	if (!texture) 
	{
		throw sdl_exception("Couldn't create texture: %s\n", SDL_GetError());
	}

	mutex = SDL_CreateMutex();

	// If you don't have this variable set you must have plugins directory
	// with the executable or libvlc_new() will not work!
	printf("VLC_PLUGIN_PATH=%s\n", getenv("VLC_PLUGIN_PATH"));

	// Initialise libVLC.
	libvlc = libvlc_new(vlc_argc, vlc_argv);
	if(NULL == libvlc) 
	{
		throw sdl_exception("LibVLC initialization failure.\n");
	}
}

void vlc_window::do_clearscreen()
{
	void *pixels;
	lock(this, &pixels);

	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);

	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, texture, NULL, &fullScreenRect);
	SDL_RenderPresent(renderer);

	unlock(this, nullptr, &pixels);
}	

void vlc_window::do_load(const char* filename)
{
	printf("Loading %s\n", filename);

	m = libvlc_media_new_path(libvlc, filename);
	mp = libvlc_media_player_new_from_media(m);
	libvlc_media_release(m);

	libvlc_video_set_callbacks(mp, lock, unlock, display, this);
	libvlc_video_set_format(mp, "RV16", fullScreenRect.w, fullScreenRect.h, fullScreenRect.w*2);
}

void vlc_window::do_play()
{
	printf("Playing\n");
	libvlc_media_player_play(mp);
}

void vlc_window::do_pause()
{
	libvlc_media_player_pause(mp);
}

void vlc_window::do_stop()
{
	// Stop stream and clean up libVLC.
	libvlc_media_player_stop(mp);
	libvlc_media_player_release(mp);
	libvlc_release(libvlc);

	do_clearscreen();

	// Close window and clean up libSDL.
	SDL_DestroyMutex(mutex);
	SDL_DestroyRenderer(renderer);
}


void vlc_window::clearscreen()
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_CLS;
	SDL_PushEvent( &evt );
}	

void vlc_window::load(const char* filename)
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_LOAD;
	evt.user.data1 = _strdup(filename);
	SDL_PushEvent( &evt );
}

void vlc_window::play()
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_PLAY;
	SDL_PushEvent( &evt );
}

void vlc_window::pause()
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_PAUSE;
	SDL_PushEvent( &evt );
}

void vlc_window::stop()
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_STOP;
	SDL_PushEvent( &evt );
}

void vlc_window::test()
{
	SDL_Event evt = {0};
	evt.user.type = MYEVT_TEST;
	SDL_PushEvent( &evt );
}

vlc_window::~vlc_window()
{
	SDL_Quit();
}

bool vlc_window::messageloop_step()
{
	SDL_Event evt;
	while (SDL_PollEvent( &evt ))
	{
		switch (evt.type) 
		{
			case SDL_QUIT:
				return true;

			case SDL_KEYDOWN:
				if (evt.key.keysym.sym == SDLK_ESCAPE)
				{
					return true;
				}
		}

		if (evt.user.type == MYEVT_PLAY)
		{
			do_play();
		}
		else if (evt.user.type == MYEVT_LOAD)
		{
			do_load( (char*)evt.user.data1);
			free(evt.user.data1);
		}
		else if (evt.user.type == MYEVT_PAUSE)
		{
			do_pause();
		}
		else if (evt.user.type == MYEVT_STOP)
		{
			do_stop();
		}
		else if (evt.user.type == MYEVT_CLS)
		{
			do_clearscreen();
		}
		else if (evt.user.type == MYEVT_TEST)
		{
			clearscreen();
			load("C:\\Users\\Deon\\Videos\\Halloween.avi"); // C:\Users\Deon\Videos\Halloween.avi
			play();
		}
	}

	return false;
}
